package study.service.security;

import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import study.domain.user.Authority;
import study.service.user.UserService;

import com.google.common.collect.Lists;

/**
 * 사용자 인증 서비스
 *
 * @author Barney Kim
 */
@Slf4j
public class UserAuthenticationService implements UserDetailsService {

	@Resource(name = "userService")
	private UserService userService;

	@Resource(name = "messageSourceAccessor")
	private MessageSourceAccessor messageSource;

	private RoleHierarchy roleHierarchy;

	public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
		this.roleHierarchy = roleHierarchy;
	}

	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		study.domain.user.User user = userService.getUserByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException(messageSource.getMessage(
					"authentication.user.not_found", new Object[] { username }));
		}
		if (!user.isEnabled()) {
			log.debug("DISABLED User={}", user);
			throw new UsernameNotFoundException(messageSource.getMessage(
					"authentication.user.disabled", new Object[] { username }));
		}
		log.debug("ENABLE User={}", user);
		Collection<GrantedAuthority> reachableGrantedAuthorities = Lists
				.newArrayList();
		List<Authority> authorities = userService.getAuthorities(user
				.getUserId());
		if (CollectionUtils.isNotEmpty(authorities)) {
			List<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
			for (Authority a : authorities) {
				grantedAuthorities.add(new GrantedAuthorityImpl(a
						.getAuthority()));
			}
			if (roleHierarchy != null) {
				reachableGrantedAuthorities = roleHierarchy
						.getReachableGrantedAuthorities(grantedAuthorities);
			} else {
				reachableGrantedAuthorities = grantedAuthorities;
			}
		}
		User suser = new User(user.getUsername(), // username
				user.getPassword(), // password
				user.isEnabled(), // enabled
				true, // accountNonExpired
				true, // credentialsNonExpred
				true, // accountNonLocked
				reachableGrantedAuthorities); // authorities
		log.debug("suser={}", suser);
		return suser;
	}

}
